#include <bits/stdc++.h>
using ll = long long;
using namespace std;
// ll n, x;
// 4分钟
// ll gcd(ll a,ll b)
// {
//     if(b==0)return a;
//     else return gcd(b,a%b);
// }
// int main()
// {
//     cin>>n>>x;
//     ll ef[n];
//     for(int i=0;i<n;i++)cin>>ef[i];
//     for(int i=0;i<n;i++)
//     {
//         if(x>=ef[i])x+=ef[i];
//         else x+=gcd(x,ef[i]);
//     }
//     cout<<x<<endl;
//     return 0;
// }

// 9分钟
// class Solution
// {
// public:
//     int maxValue(vector<vector<int>> &grid)
//     {
//         int m = grid.size(), n = grid[0].size();
//         vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
//         dp[0][0] = 0;
//         for (int i = 1; i <= m; i++)
//         {
//             for (int j = 1; j <= n; j++)
//             {
//                 dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + grid[i - 1][j - 1];
//             }
//         }
//         return dp[m][n];
//     }
// };
// int main()
// {
//     vector<vector<int>> input{{1,3,1},{1,5,1},{4,2,1}};
//     cout<<Solution().maxValue(input)<<endl;
//     return 0;
// }

// https://ac.nowcoder.com/acm/problem/214850
// 双指针遍历输入字符的left和right指向的位置
// 如果它们中存在相同的字符，就接着判断，如果最后设置的变量
// 为true，证明是可以的，否则不可以
// int t, n, i;
// string s;
// bool hash1[26], hash2[26];
// int main()
// {
//     cin >> t;
//     while (t--)
//     {
//         cin >> n;
//         if(n==1)cout<<"Yes"<<endl;
//         else
//         {
//             vector<string> rets(n);
//             int left=0,right=n-1;
//             while(n--)cin>>rets[i++];
//             bool exist=true;
//             while(left<right)
//             {
//                 memset(hash1,0,sizeof (hash1));
//                 memset(hash2,0,sizeof(hash2));
//                 for(auto& x:rets[left])hash1[x]=true;
//                 for(auto& x:rets[right])hash2[x]=true;
//                 bool found=false;
//                 for(int j=0;j<26;j++)
//                 {
//                     if(hash1[j]&&hash2[j])
//                     {
//                         found=true;
//                         break;
//                     }
//                 }
//                 if(!found)
//                 {
//                     exist=false;
//                     break;
//                 }
//             }
//             cout<<(exist?"Yes":"No")<<endl;
//         }
//     }
//     return 0;
// }

//https://www.nowcoder.com/practice/88f7e156ca7d43a1a535f619cd3f495c?tpId=308&tqId=40470&ru=/exam/oj
//拓扑排序-BFS
// 1.建图——存储信息
// 2.统计入度，把所有入度为0的点，加入到队列中
// 3.当队列不为空时
//      1.拿出队头元素
//      2.修改队头元素连接的点的信息（入读）
//      3.判断，如果入度变成0，再加入到队列中
// int n,m;
// int main()
// {
//     cin>>n>>m;
//     vector<vector<bool>> ret(n+1,vector<bool>(n+1,0));
//     for(int i=1;i<=n;i++)
//     {
//         int a,b;
//         cin>>a>>b;
//         ret[a][b]=1;
//     }
//     queue<bool> q;
//     for(int i=1;i<=n;i++)
//     {
//         for(int j=1;j<=n;j++)
//         {
//             if(!ret[i][j])q.push(ret[i][j]);
//         }
//     }
    
// }

//https://www.nowcoder.com/practice/88f7e156ca7d43a1a535f619cd3f495c?tpId=308&tqId=40470&ru=/exam/oj

// const int N=2e5+10;
// int etop,n,m;
// stack<int> ans;
// bool valid=true;
// //对结构体里应该存什么信息还是有点模糊
// //还是使用链表模拟的
// struct Edge
// {
//     int u,v;
//     // next不是指向下一条边的起点和终点，而是指向同一个起点的另一条边
//     Edge* next;
// }epool[N];

// struct Node
// {
//     /**
//      * 0:没有搜到
//      * 1:搜索完成
//      * -1:正在搜索中
//      */
//     int mark;
//     Edge* first;//指向从该节点出发的第一条边
// }nodes[N];
// void AddEdge(int u,int v)
// {
//     // 假设有边：1->2, 1->3, 1->4

//     // 初始状态：
//     // Node[1]: first = nullptr

//     // 添加边1->2后：
//     // Node[1]: first -> Edge{u=1,v=2,next=nullptr}

//     // 添加边1->3后：
//     // Node[1]: first -> Edge{u=1,v=3,next-> Edge{u=1,v=2,next=nullptr}}

//     // 添加边1->4后：
//     // Node[1]: first -> Edge{u=1,v=4,next-> Edge{u=1,v=3,next-> Edge{u=1,v=2,next=nullptr}}}

//     epool[etop].u=u;
//     epool[etop].v=v;
//     //存储的一定是边的信息
//     //这里是将epool[etop]的next指针置为空，前一个保存的边的信息还是存在的
//     epool[etop].next=nodes[u].first;
//     //这里更新的是当前插入的节点的信息，之前的边的信息都存在next指针里了
//     nodes[u].first=&epool[etop];
//     etop++;
// }

// void dfs(int u)
// {
//     if(nodes[u].mark==-1)
//     {
//         valid=false;
//         return;
//     }
//     if(nodes[u].mark==1)return;
//     nodes[u].mark=-1;
//     Edge* e=nodes[u].first;

//     while(e!=nullptr)
//     {
//         dfs(e->v);
//         e=e->next;
//     }
//     ans.push(u);
//     nodes[u].mark=1;
// }

// int main()
// {
//     cin>>n>>m;
//     for(int i=1;i<=m;i++)
//     {
//         int a,b;
//         cin>>a>>b;
//         AddEdge(a,b);
//     }
//     for(int i=1;i<=n;i++)dfs(i);
//     if(valid)
//     {
//         while(!ans.empty())
//         {
//             if(ans.size()!=1)
//             {
//                 cout<<ans.top()<<" ";
//                 ans.pop();
//             }
//             else
//             {
//                 cout<<ans.top();
//                 ans.pop();
//             }
//         }
//         cout<<endl;
//     }
//     else cout<<-1<<endl;
//     return 0;
// }

const int N=2e5+10;
int n,m;
//不像一个二维数组，像一个链表
//Edge[i]中存放的是起点指向的所有点
vector<int> Edge[N];
int in[N];//统计入度
void topoSort()
{
    vector<int> res;
    queue<int> q;
    for(int i=1;i<=n;i++)if(!in[i])q.push(i);
    
    while(!q.empty())
    {
        int cur=q.front();//拿到的是Edge[i]
        q.pop();
        res.push_back(cur);
        for(int next:Edge[cur])
        {
            in[next]--;
            if(in[next]==0)
                q.push(next);
        }
    }
    if(res.size()==n-1)
    {
        cout<<-1<<endl;
        return;
    }
    for(int i=0;i<res.size();i++)
    {
        if(i==n-1)
            cout<<res[i];
        else cout<<res[i]<<" ";
    }
    cout<<endl;
    return;
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        Edge[a].push_back(b);
        in[b]++;
    }
    topoSort();
    return 0;
}











